package com.googlecode.mbhsrobopro.controller.components;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Calendar;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.googlecode.mbhsrobopro.controller.Test;
import com.googlecode.mbhsrobopro.controller.events.ValueChangedEvent;
import com.googlecode.mbhsrobopro.controller.listeners.ValueChangedListener;

/**
 * The graphical user interface for rover control. Displays current readings, motor speed, and turning scale. 
 * Also allows for control of rover movement, motor speed, and turning scale. The graphical user supports two 
 * control schemes: 
 * <ul>
 * <li>Original Control - Values controlled with keyboard commands.</li>
 * <li>Arcade Drive - Rover controlled using the mouse location on a grid</li>
 * </ul>
 * 
 * @see ArcadeDrive
 * 
 * @author Brian Clanton
 *
 */

public class ProgramController extends JFrame implements KeyListener, ChangeListener, ValueChangedListener {

	private static final String dataDir = "data/";
	
	public static final int FRONT_LEFT = 0, FRONT_RIGHT = 1;
	
	private JLabel thermistor;
	private JLabel photocell1, photocell2;
	private JLabel motorSpeed;
	private JLabel light;
	private JLabel scaleValue;

	private JTabbedPane tabs;

	private ArcadeDrive ad;

	private JSlider turningScale;

	private boolean right = false, left = false, forward = false, backward = false;
	private boolean normalControl = true, lineControl = false;

	private int motorValue = 512;
	private int lightValue = 480;
	
	private double scale;

	private boolean controlOne, controlTwo;

	public ProgramController() {
		super("RoboPro Wireless Interaction Controller");

		JPanel readingsBorder = new JPanel(new FlowLayout(10, 10, FlowLayout.LEFT));
		JPanel readings = new JPanel(new GridLayout(6, 1));
		motorSpeed = new JLabel("Motor Speed: " + motorValue);

		light = new JLabel("Light Value: " + lightValue);
		
		thermistor = new JLabel("Thermistor Reading: ");
		
		photocell1 = new JLabel("Front Left Photocell Reading: ");
		photocell2 = new JLabel("Front Right Photocell Reading: ");

		scaleValue = new JLabel("Turning Scale: 6/12");

		readings.add(motorSpeed);
		readings.add(light);
		readings.add(thermistor);
		readings.add(photocell1);
		readings.add(photocell2);
		readings.add(scaleValue);

		readingsBorder.add(readings);

		JPanel originalControl = new JPanel(new FlowLayout(25, 25, FlowLayout.CENTER));

		turningScale = new JSlider(3, 9);
		turningScale.setMajorTickSpacing(1);
		turningScale.setPaintTicks(true);
		turningScale.setSnapToTicks(true);
		turningScale.addChangeListener(this);
		turningScale.setFocusable(false);

		originalControl.add(turningScale);

		ad = new ArcadeDrive();
		ad.addValueChangedListener(this);

		tabs = new JTabbedPane();
		tabs.addTab("Original Control", originalControl);
		//tabs.addTab("Mouse Control", ad);	
		tabs.addChangeListener(this);

		addKeyListener(this);

		JPanel pane = new JPanel();
		pane.setLayout(new BorderLayout());
		pane.add(readingsBorder, BorderLayout.NORTH);
		pane.add(tabs, BorderLayout.CENTER);

		add(pane);
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				int option = JOptionPane.showConfirmDialog(null, "Save Data to File?", "Closing Controller", JOptionPane.YES_NO_OPTION);
				
				if (option == JOptionPane.YES_OPTION) {
					try {		
						// Creates data directory if it does not already exist in the project
						File dir = new File(dataDir);
						if (!dir.exists())
							dir.mkdir();

						// Makes file name from current date and time
						Calendar cal = Calendar.getInstance();
						String day = "" + (cal.get(Calendar.MONTH) + 1) + "-" + cal.get(Calendar.DATE) + "-" + cal.get(Calendar.YEAR);
						String time = "" + (cal.get(Calendar.HOUR) == 0 ? 12 : cal.get(Calendar.HOUR)) + "-" + 
						(cal.get(Calendar.MINUTE) < 10 ? "0" + cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)) + "-" +
						(cal.get(Calendar.SECOND) < 10 ? "0" + cal.get(Calendar.SECOND) : cal.get(Calendar.SECOND));
						String filename = dataDir + day + " " + time + ".txt";
						BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filename)));
						// Write Headers
						writer.write(Test.getHeader());
						// Write Data
						for(int i = 0; i < Test.NUM_LABELS; i++) {
							String line = "";
							
							for (String s : Test.labels)
								line += s + "\t";
							
							line = line.substring(0, line.lastIndexOf("\t")) + "\n";
							
							writer.write(line);
						}
						
						writer.flush();
						writer.close();
						
						// Confirmation
						JOptionPane.showMessageDialog(null, "Data written to file: " + filename);
					} catch (IOException e1) {
						JOptionPane.showMessageDialog(null, "Error in writing data to file.");
					}
				}
			}
		});
		
		pack();

		new DynamicGraph(180, 5000, 3, 95);

		Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
		setLocation(new Point(size.width / 2 - this.getWidth() / 2, size.height / 2 - this.getHeight() / 2));

		setResizable(false);
		setVisible(true);
		requestFocus();
	}

	public void setThermistorReading(int reading) {
		thermistor.setText("Thermistor Reading: " + reading);
	}
	
	public void setPhotocellReading(int reading, int number) {
		if (number == FRONT_LEFT)
			photocell1.setText("Front Left Photocell Reading: " + reading);
		else if (number == FRONT_RIGHT)
			photocell2.setText("Front Right Photocell Reading: " + reading);
	}

	public double getScale() {
		return scale;
	}

	public int getMotorSpeed() {
		return motorValue;
	}
	
	public int getLightValue() {
		return lightValue;
	}

	public boolean isRight() {
		return right;
	}

	public boolean isLeft() {
		return left;
	}

	public boolean isForward() {
		return forward;
	}

	public boolean isBackward() {
		return backward;
	}

	public boolean isNormalControl() {
		return normalControl;
	}

	public boolean isLineControl() {
		return lineControl;
	}

	@Override
	public void keyPressed(KeyEvent e) {
		int key = e.getKeyCode();
		if (key == KeyEvent.VK_N) {
			normalControl = true;
			lineControl = false;
		}
		if (key == KeyEvent.VK_L) {
			normalControl = false;
			lineControl = true;
		}
		if (key == KeyEvent.VK_RIGHT)
			right = true;
		if (key == KeyEvent.VK_LEFT)
			left = true;
		if (key == KeyEvent.VK_UP)
			forward = true;
		if (key == KeyEvent.VK_DOWN)
			backward = true;
		if (key == KeyEvent.VK_Z)
			turningScale.setValue(turningScale.getValue() - 1);
		if (key == KeyEvent.VK_X)
			turningScale.setValue(turningScale.getValue() + 1);

//		if (controlOne) {
			if (key == KeyEvent.VK_PERIOD) {
				motorValue += motorValue + 24 > 512 ? 0 : 24;
				motorSpeed.setText("Motor Speed: " + motorValue);
			}	
			if (key == KeyEvent.VK_COMMA) {
				motorValue -= motorValue - 24 < -512 ? 0 : 24;
				motorSpeed.setText("Motor Speed: " + motorValue);
			}
			if (key == KeyEvent.VK_S) {
				lightValue += lightValue + 24 > 512 ? 0 : 24;
				light.setText("Light Value: " + lightValue);
			}	
			if (key == KeyEvent.VK_A) {
				lightValue -= lightValue - 24 < -512 ? 0 : 24;
				light.setText("Light Value: " + lightValue);
			}
//		}

		if (key == KeyEvent.VK_ESCAPE)
			System.exit(0);
	}

	@Override
	public void keyReleased(KeyEvent e) {
		int key = e.getKeyCode();
		if(key == KeyEvent.VK_RIGHT)
			right = false;
		if(key == KeyEvent.VK_LEFT)
			left = false;
		if(key == KeyEvent.VK_UP)
			forward = false;
		if(key == KeyEvent.VK_DOWN)
			backward = false;
	}

	@Override
	public void keyTyped(KeyEvent e) {

	}

	@Override
	public void stateChanged(ChangeEvent e) {
		if (e.getSource() == turningScale) {
			scale = ((double) turningScale.getValue()) / 12;
			scaleValue.setText("Turning Scale: " + turningScale.getValue() + "/12");
		} else if (e.getSource() == tabs) {
			controlOne = tabs.getSelectedIndex() == 0;
			controlTwo = tabs.getSelectedIndex() == 1;

			if (controlOne) {
				ad.zero();
				motorValue = 512;
				scale = .5;
				requestFocus();
			} else if (controlTwo) {
				ad.zero();
				ad.requestFocus();
			}
		}
	}

	@Override
	public void valueChanged(ValueChangedEvent e) {
		if (tabs.getSelectedIndex() == 1) {
			motorValue = e.getMotorSpeed();
			motorSpeed.setText("Motor Speed: " + motorValue);
			scale = e.getTurningScale();
			scaleValue.setText("Turning Scale: " + scale);
			forward = e.isForward();
			backward = e.isBackward();
			left = e.isLeft();
			right = e.isRight();
		}
	}

}
